// tracker_test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define BOOST_TEST_MODULE tracker_test
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include "../tracker/fast_trigonometries.h"
#include "../tracker/draw_obj.h"

BOOST_AUTO_TEST_SUITE(geometry_elements_test)

BOOST_AUTO_TEST_CASE (geometry_elements_size)
{
  BOOST_CHECK_EQUAL(sizeof(point_2),          16);
  BOOST_CHECK_EQUAL(sizeof(segment_2),        32);
  BOOST_CHECK_EQUAL(sizeof(box_2),            32);
  BOOST_CHECK_EQUAL(sizeof(angle_box_2),      40);
  BOOST_CHECK_EQUAL(sizeof(ring_2),           24);
  BOOST_CHECK_EQUAL(sizeof(arc_2),            32);
  BOOST_CHECK_EQUAL(sizeof(annulus_2),        32);
  BOOST_CHECK_EQUAL(sizeof(annulus_arc_2),    40);
  BOOST_CHECK_EQUAL(sizeof(polygon_2),        20);
  BOOST_CHECK_EQUAL(sizeof(shape_2),          48);
}

BOOST_AUTO_TEST_CASE (point_2_construction)
{
  point_2 pt_0;
  BOOST_CHECK_EQUAL(pt_0.x, 0l);
  BOOST_CHECK_EQUAL(pt_0.y, 0l);

  point_2 pt_i(1, 3);
  BOOST_CHECK_EQUAL(pt_i.x, 1l);
  BOOST_CHECK_EQUAL(pt_i.y, 3l);

  point_2 pt_l(1l, 3l);
  BOOST_CHECK_EQUAL(pt_l.x, 1l);
  BOOST_CHECK_EQUAL(pt_l.y, 3l);
}

BOOST_AUTO_TEST_CASE (box_2_construction)
{
  box_2 box_0;
  BOOST_CHECK_EQUAL(box_0.top_left.x, 0l);
  BOOST_CHECK_EQUAL(box_0.top_left.y, 0l);
  BOOST_CHECK_EQUAL(box_0.bottom_right.x, 0l);
  BOOST_CHECK_EQUAL(box_0.bottom_right.y, 0l);

  point_2 pt_i_0(1, 3), pt_i_1(1.3f, 3.5f);
  box_2 box_i(pt_i_0, pt_i_1);
  BOOST_CHECK_EQUAL(box_i.top_left, pt_i_0);
  BOOST_CHECK_EQUAL(box_i.bottom_right, pt_i_1);
}

BOOST_AUTO_TEST_CASE (box_2_serialization)
{
  std::string filename(boost::archive::tmpdir());
  filename += "\\box_2_serialization.xml";

  point_2 pt_i_0(1, 3), pt_i_1(1.3f, 3.5f);
  box_2 box_i(pt_i_0, pt_i_1), box_r;

  {
	  std::ofstream ofs(filename);
	  BOOST_CHECK(ofs.good());
	
	  boost::archive::xml_oarchive oa(ofs);
	  oa << BOOST_SERIALIZATION_NVP(box_i);
  }

  {
	  std::ifstream ifs(filename);
	  BOOST_CHECK(ifs.good());
	
	  boost::archive::xml_iarchive ia(ifs);
	  ia >> BOOST_SERIALIZATION_NVP(box_r);
  }

  BOOST_CHECK_EQUAL(box_r.top_left, box_i.top_left);
  BOOST_CHECK_EQUAL(box_r.bottom_right, box_i.bottom_right);

  std::remove(filename.c_str());
}

BOOST_AUTO_TEST_CASE (polygon_2_serialization)
{
  std::string filename(boost::archive::tmpdir());
  filename += "\\polygon_2_serialization.xml";

  shape_2 poly = polygon_2();

  boost::get<polygon_2>(poly).push_back(point_2(3, 5));
  boost::get<polygon_2>(poly).push_back(point_2(6, 7));
  boost::get<polygon_2>(poly).push_back(point_2(8, 9));

  {
    std::ofstream ofs(filename);
    BOOST_CHECK(ofs.good());

    boost::archive::xml_oarchive oa(ofs);
    oa << BOOST_SERIALIZATION_NVP(poly);
  }

  shape_2 poly_r;

  {
    std::ifstream ifs(filename);
    BOOST_CHECK(ifs.good());

    boost::archive::xml_iarchive ia(ifs);
    ia >> BOOST_SERIALIZATION_NVP(poly_r);
  }

  BOOST_CHECK_EQUAL(poly, poly_r);

  std::remove(filename.c_str());
}

BOOST_AUTO_TEST_CASE (angle_math_test)
{
  const double tol = 0.000001;

  BOOST_CHECK_EQUAL(angle_math::normalize(12), 12);
  BOOST_CHECK_EQUAL(angle_math::normalize(-12), 348);
  BOOST_CHECK_EQUAL(angle_math::normalize(-372), 348);
  BOOST_CHECK_EQUAL(angle_math::normalize(727), 7);
  BOOST_CHECK_EQUAL(angle_math::normalize(360), 0);
  BOOST_CHECK_EQUAL(angle_math::sweep(3, 360), 357);
  BOOST_CHECK_EQUAL(angle_math::sweep(357, 3), 6);

  BOOST_CHECK_CLOSE_FRACTION(angle_math::normalize(360.0),    0.0,      tol);
  BOOST_CHECK_CLOSE_FRACTION(angle_math::normalize(360.0001), 0.0001,   tol);
  BOOST_CHECK_CLOSE_FRACTION(angle_math::normalize(-0.0001),  359.9999, tol);
  BOOST_CHECK_CLOSE_FRACTION(angle_math::normalize(0.0),      0.0,      tol);
  BOOST_CHECK_CLOSE_FRACTION(angle_math::normalize(-27.0),    333.0,    tol);
}

BOOST_AUTO_TEST_CASE (point_interpolation)
{
}

BOOST_AUTO_TEST_CASE (distance_of_point_to_segment)
{
  point_2 pt0(0, 0), pt1(1, 0);
  segment_2 seg2(pt0, pt1);
  const double tol = 0.01;
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(2, 0)),   1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(2, 1)),   1.414,  tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(1, 1)),   1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(0, 1)),   1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(-1, 1)),  1.414,  tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(-1, 0)),  1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(-1, -1)), 1.414,  tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(0, -1)),  1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(1, -1)),  1.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(2, -1)),  1.414,  tol);
  BOOST_CHECK_CLOSE_FRACTION(seg2.distance(point_2(0, 0)),   0.0,    tol);

  point_2 pt2(100, 100);
  segment_2 seg3(pt0, pt2);
  BOOST_CHECK_CLOSE_FRACTION(seg3.distance(point_2(50, 50)), 0.0,    tol);
  BOOST_CHECK_CLOSE_FRACTION(seg3.distance(point_2(100, 0)), 70.711, tol);
}

BOOST_AUTO_TEST_CASE (quadrant_code)
{
  vector_2 vec0(1, 0), vec1(1, 1);
  BOOST_CHECK(vec1.left(vec0));

  point_2 pt0(0, 0);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(pt0, point_2(10, 1)),   draw_obj::kQuadrantI);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(pt0, point_2(10, -1)),  draw_obj::kQuadrantI);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(pt0, point_2(10, 9)),   draw_obj::kQuadrantVIII);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(pt0, point_2(9, 10)),   draw_obj::kQuadrantVIII);

  BOOST_CHECK_EQUAL(draw_obj::quadrant(0),   draw_obj::kQuadrantI);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(20),  draw_obj::kQuadrantI);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(40),  draw_obj::kQuadrantII);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(60),  draw_obj::kQuadrantII);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(80),  draw_obj::kQuadrantIII);
  BOOST_CHECK_EQUAL(draw_obj::quadrant(100), draw_obj::kQuadrantIII);
}

BOOST_AUTO_TEST_CASE (angle_box_vertexes)
{
  angle_box_2 ab0(3, 3, 1, 1, 0);
  BOOST_CHECK_EQUAL(ab0.top_left(),     point_2(2, 2));
  BOOST_CHECK_EQUAL(ab0.top_right(),    point_2(4, 2));
  BOOST_CHECK_EQUAL(ab0.bottom_left(),  point_2(2, 4));
  BOOST_CHECK_EQUAL(ab0.bottom_right(), point_2(4, 4));

  angle_box_2 ab1(3, 3, 1, 1, 360);
  BOOST_CHECK_EQUAL(ab1.top_left(),     point_2(2, 2));
  BOOST_CHECK_EQUAL(ab1.top_right(),    point_2(4, 2));
  BOOST_CHECK_EQUAL(ab1.bottom_left(),  point_2(2, 4));
  BOOST_CHECK_EQUAL(ab1.bottom_right(), point_2(4, 4));

  angle_box_2 ab3(3, 3, 1, 1, 90);
  BOOST_CHECK_EQUAL(ab3.top_left(),     point_2(2, 4));
  BOOST_CHECK_EQUAL(ab3.top_right(),    point_2(2, 2));
  BOOST_CHECK_EQUAL(ab3.bottom_left(),  point_2(4, 4));
  BOOST_CHECK_EQUAL(ab3.bottom_right(), point_2(4, 2));

  angle_box_2 ab4(3, 3, 1, 1, 180);
  BOOST_CHECK_EQUAL(ab4.top_left(),     point_2(4, 4));
  BOOST_CHECK_EQUAL(ab4.top_right(),    point_2(2, 4));
  BOOST_CHECK_EQUAL(ab4.bottom_left(),  point_2(4, 2));
  BOOST_CHECK_EQUAL(ab4.bottom_right(), point_2(2, 2));
}

BOOST_AUTO_TEST_CASE (handle_count)
{
  draw_obj point_obj(_T("point_2"),                     point_2(),       0, -1);
  draw_obj segment_obj(_T("segment_2"),                 segment_2(),     0, -1);
  draw_obj box_obj(_T("box_2"),                         box_2(),         0, -1);
  draw_obj angle_box_obj(_T("angle_box_2"),             angle_box_2(),   0, -1);
  draw_obj ring_obj(_T("ring_2"),                       ring_2(),        0, -1);
  draw_obj arc_obj(_T("arc_2"),                         arc_2(),         0, -1);
  draw_obj annulus_obj(_T("annulus_2"),                 annulus_2(),     0, -1);
  draw_obj annulus_sector_obj(_T("annulus_arc_2"),      annulus_arc_2(), 0, -1);
  draw_obj polygon_obj(_T("polygon_2"),                 polygon_2(),     0, -1);

  boost::get<polygon_2>(polygon_obj.data()).push_back(point_2(3, 5));
  boost::get<polygon_2>(polygon_obj.data()).push_back(point_2(6, 7));
  boost::get<polygon_2>(polygon_obj.data()).push_back(point_2(8, 9));

  BOOST_CHECK_EQUAL(point_obj.get_handle_count(),           1);
  BOOST_CHECK_EQUAL(segment_obj.get_handle_count(),         2);
  BOOST_CHECK_EQUAL(box_obj.get_handle_count(),             8);
  BOOST_CHECK_EQUAL(angle_box_obj.get_handle_count(),       8);
  BOOST_CHECK_EQUAL(ring_obj.get_handle_count(),            4);
  BOOST_CHECK_EQUAL(arc_obj.get_handle_count(),             2);
  BOOST_CHECK_EQUAL(annulus_obj.get_handle_count(),         8);
  BOOST_CHECK_EQUAL(annulus_sector_obj.get_handle_count(),  4);
  BOOST_CHECK_EQUAL(polygon_obj.get_handle_count(),         3);
}

BOOST_AUTO_TEST_SUITE_END()

